﻿using System;

namespace Aeon.Emulator.Memory
{
    /// <summary>
    /// Represents a real-mode memory address.
    /// </summary>
    [CLSCompliant(false)]
    public struct RealModeAddress : IEquatable<RealModeAddress>
    {
        private ushort segment;
        private ushort offset;

        /// <summary>
        /// Initializes a new instance of the <see cref="RealModeAddress"/> struct.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <param name="offset">The offset.</param>
        public RealModeAddress(ushort segment, ushort offset)
        {
            this.segment = segment;
            this.offset = offset;
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="entryA">The entry A.</param>
        /// <param name="entryB">The entry B.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(RealModeAddress entryA, RealModeAddress entryB)
        {
            return entryA.Equals(entryB);
        }
        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="entryA">The entry A.</param>
        /// <param name="entryB">The entry B.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(RealModeAddress entryA, RealModeAddress entryB)
        {
            return !entryA.Equals(entryB);
        }

        /// <summary>
        /// Gets the segment value.
        /// </summary>
        public ushort Segment
        {
            get { return this.segment; }
        }
        /// <summary>
        /// Gets the offset value.
        /// </summary>
        public ushort Offset
        {
            get { return this.offset; }
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("{0:X4}:{1:X4}", this.segment, this.offset);
        }
        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        /// True if the specified <see cref="System.Object"/> is equal to this instance; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if(obj is RealModeAddress)
                return Equals((RealModeAddress)obj);
            else
                return false;
        }
        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return (this.segment << 16) | this.offset;
        }
        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// True if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        public bool Equals(RealModeAddress other)
        {
            return this.segment == other.segment && this.offset == other.offset;
        }
    }
}
